import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListCellRenderer;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableCellRenderer;

public class MatrixPanel extends JPanel {
	
	private JPanel matrixSelectPanel;
	private JPanel matrixDisplayPanel;
	private JPanel displayMatricesPanel;
	private JPanel solutionPanel;
	private JPanel infoPanel;
	
	private JLabel errorLabel;
	private JLabel spacing1;
	private JLabel spacing2;
	private JLabel spacing3;
	private JLabel spacing4;
	private JLabel matrix1Label;
	private JLabel matrix2Label;
	private JLabel buildLabel;
	
	private JComboBox matrix1HeightBox;
	private JComboBox matrix1WidthBox;
	private JComboBox matrix2HeightBox;
	private JComboBox matrix2WidthBox; 
	private JComboBox operationBox;
	
	private Integer[] height = {1, 2 , 3, 4};
	private Integer[] width = {1, 2, 3, 4};
	private String[] operations = {"+", "-", "x", "Gauss Jordan"};
	private JLabel heightlabel1;
	private JLabel widthlabel1;
	private JLabel heightlabel2;
	private JLabel widthlabel2;
	private JLabel operation;
	private JButton buildButton;
	private JPanel buttonPanel;
	private JButton calcButton;
	private JButton randomPopButton;
	
	private int selection1H=1;
	private int selection1W=1;
	private int selection2H=1;
	private int selection2W=1; 
	private String selectionOp="+"; 
	
	private JTable table1;
	private JTable table2;
	private JTable table3; 
	private Double [][] solutionMatrix;
	
	public MatrixPanel()
	{	
		this.setBackground(Color.white);
		this.setLayout(new BorderLayout());				
		
		buildMatrixSelectPanel();
		buildMatrixDisplayPanel();
		
		//new panel in borderlayout.east (grid panel) and add matrix select
		//panel in this grid layout 
		
		//matrixSelectPanel.add(gridInEast);
		add(matrixSelectPanel, BorderLayout.EAST);
		add(displayMatricesPanel, BorderLayout.CENTER);
		
		setVisible(true);
		
	}
	
	private void buildMatrixSelectPanel(){
		matrixSelectPanel = new JPanel();
		
		matrixSelectPanel.setPreferredSize(new Dimension(200,0));
		matrixSelectPanel.setLayout(new BoxLayout(matrixSelectPanel, BoxLayout.Y_AXIS));
		
		buildButton = new JButton("Build Matrix");
	
		heightlabel1 = new JLabel("Height: ");
		widthlabel1 = new JLabel("Width: ");
		heightlabel2 = new JLabel("Height: ");
		widthlabel2 = new JLabel("Width: ");
		operation = new JLabel("Matrix Operation");
		
		spacing1 = new JLabel("    ");
		spacing2 = new JLabel("    ");
		spacing3 = new JLabel("    ");
		spacing4 = new JLabel("    ");
		matrix1Label = new JLabel("Matrix 1 Dimensions ");
		matrix2Label = new JLabel("Matrix 2 Dimensions ");
		buildLabel = new JLabel("Build Matrices ");
		
		matrix1Label.setFont(new Font("Dialog", 1, 14));
		matrix2Label.setFont(new Font("Dialog", 1, 14));
		operation.setFont(new Font("Dialog", 1, 14));
		buildLabel.setFont(new Font("Dialog", 1, 14));
		
		buildButton.addActionListener(new buildButtonListener());
		
		operationBox = new JComboBox(operations);
		operationBox.setMaximumSize(new Dimension(75, 20));
	
		matrix1HeightBox = new JComboBox(height);
		matrix1HeightBox.setMaximumSize(new Dimension(31, 20));
		
		matrix1WidthBox = new JComboBox(width);
		matrix1WidthBox.setMaximumSize(new Dimension(31, 20));
		
		matrix2HeightBox = new JComboBox(height);
		matrix2HeightBox.setMaximumSize(new Dimension(31, 20));
		
		matrix2WidthBox = new JComboBox(width);
		matrix2WidthBox.setMaximumSize(new Dimension(31, 20));
		
		operationBox.addActionListener(new operationListener());
		matrix1HeightBox.addActionListener(new ComboBoxListener());
		matrix1WidthBox.addActionListener(new ComboBoxListener());
		matrix2HeightBox.addActionListener(new ComboBoxListener());
		matrix2WidthBox.addActionListener(new ComboBoxListener());
		
		matrix1Label.setAlignmentX(CENTER_ALIGNMENT);
		matrix2Label.setAlignmentX(CENTER_ALIGNMENT);
		operationBox.setAlignmentX(CENTER_ALIGNMENT);
		matrix1HeightBox.setAlignmentX(CENTER_ALIGNMENT);
		matrix1WidthBox.setAlignmentX(CENTER_ALIGNMENT);
		matrix2HeightBox.setAlignmentX(CENTER_ALIGNMENT);
		matrix2WidthBox.setAlignmentX(CENTER_ALIGNMENT);
		heightlabel1.setAlignmentX(CENTER_ALIGNMENT);
		widthlabel1.setAlignmentX(CENTER_ALIGNMENT);
		heightlabel2.setAlignmentX(CENTER_ALIGNMENT);
		widthlabel2.setAlignmentX(CENTER_ALIGNMENT);
		operation.setAlignmentX(CENTER_ALIGNMENT);
		operationBox.setAlignmentX(CENTER_ALIGNMENT);
		buildButton.setAlignmentX(CENTER_ALIGNMENT);
		buildLabel.setAlignmentX(CENTER_ALIGNMENT);
		
		matrixSelectPanel.add(matrix1Label);
		JPanel grid1 = new JPanel();
		grid1.setLayout(new GridLayout(1, 2));
		grid1.add(heightlabel1);
		grid1.add(matrix1HeightBox);
		grid1.setAlignmentX(CENTER_ALIGNMENT);
		matrixSelectPanel.add(Box.createRigidArea(new Dimension(0,10)));
		grid1.setMaximumSize(new Dimension(100, 20));
		matrixSelectPanel.add(grid1);
		
		JPanel grid2 = new JPanel();
		grid2.setLayout(new GridLayout(1, 2));
		grid2.add(widthlabel1);
		grid2.add(matrix1WidthBox);
		grid2.setAlignmentX(CENTER_ALIGNMENT);
		grid2.setMaximumSize(new Dimension(100, 20));
		matrixSelectPanel.add(grid2);
		matrixSelectPanel.add(spacing1);
		

		matrixSelectPanel.add(matrix2Label);
		matrixSelectPanel.add(Box.createRigidArea(new Dimension(0,15)));
		JPanel grid3 = new JPanel();
		grid3.setLayout(new GridLayout(1, 2));
		grid3.add(heightlabel2);
		grid3.add(matrix2HeightBox);
		grid3.setAlignmentX(CENTER_ALIGNMENT);
		grid3.setMaximumSize(new Dimension(100, 20));
		matrixSelectPanel.add(grid3);
		
		JPanel grid4 = new JPanel();
		grid4.setLayout(new GridLayout(1, 2));
		grid4.add(widthlabel2);
		grid4.add(matrix2WidthBox);
		grid4.setAlignmentX(CENTER_ALIGNMENT);
		grid4.setMaximumSize(new Dimension(100, 20));
		matrixSelectPanel.add(grid4);
		matrixSelectPanel.add(spacing2);
	
		matrixSelectPanel.add(Box.createRigidArea(new Dimension(0,15)));
		matrixSelectPanel.add(operation);
		matrixSelectPanel.add(operationBox);
		matrixSelectPanel.add(spacing4);
		
		matrixSelectPanel.add(Box.createRigidArea(new Dimension(0, 15)));
		matrixSelectPanel.add(buildLabel);
		buildButton.setPreferredSize(new Dimension(10, 40));
		matrixSelectPanel.add(buildButton);
		matrixSelectPanel.add(spacing3);
	}
	
	private void buildMatrixDisplayPanel(){
		solutionPanel = new JPanel();
		solutionPanel.setBackground(Color.white);
		solutionPanel.setAlignmentX(CENTER_ALIGNMENT);
		
		solutionPanel.setAlignmentY(CENTER_ALIGNMENT);
		
		infoPanel = new JPanel();
		infoPanel.setPreferredSize(new Dimension(0, 100));
		infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.Y_AXIS));
		
		displayMatricesPanel = new JPanel();
		displayMatricesPanel.setLayout(new BorderLayout());
		
		
		matrixDisplayPanel = new JPanel();
		matrixDisplayPanel.setBackground(Color.white);
		
		displayMatricesPanel.add(matrixDisplayPanel, BorderLayout.NORTH);
		displayMatricesPanel.add(solutionPanel, BorderLayout.CENTER);
		displayMatricesPanel.add(infoPanel, BorderLayout.SOUTH);
	}
	
	private class operationListener implements ActionListener{

		public void actionPerformed(ActionEvent e) {
			selectionOp = (String)operationBox.getSelectedItem();
		}
	}
	
	private class ComboBoxListener implements ActionListener{

		public void actionPerformed(ActionEvent e) {
			selection1H = (Integer)matrix1HeightBox.getSelectedItem();
			selection1W = (Integer)matrix1WidthBox.getSelectedItem();
			selection2H = (Integer)matrix2HeightBox.getSelectedItem();
			selection2W = (Integer)matrix2WidthBox.getSelectedItem();
						
		}
	}
	
	private class buildButtonListener implements ActionListener{
		public void actionPerformed(ActionEvent e){
			
			matrixDisplayPanel.removeAll();
			solutionPanel.removeAll();
			infoPanel.removeAll();
			
			table1 = new JTable(selection1H, selection1W);
			table2 = new JTable(selection2H, selection2W);
			
			table1.setBackground(new Color(0x00746b));
			table2.setBackground(new Color(0x00746b));
			table1.setForeground(Color.white);
			table2.setForeground(Color.white);
			table1.setFont(new Font("Dialog", 1, 14));
			table2.setFont(new Font("Dialog", 1, 14));
			table1.setAlignmentX(CENTER_ALIGNMENT);
			table2.setAlignmentX(CENTER_ALIGNMENT);
			table1.setGridColor(Color.white);
			table2.setGridColor(Color.white);
			
			
			
			for(int i=0; i<table1.getRowCount(); i++){
				for(int j=0; j<table1.getColumnCount(); j++){
					table1.setValueAt("0", i, j);
				}
			}
			
			for(int i=0; i<table2.getRowCount(); i++){
				for(int j=0; j<table2.getColumnCount(); j++){
					table2.setValueAt("0", i, j);
				}
			}

			JLabel operation = new JLabel(selectionOp);
			
			matrixDisplayPanel.add(table1);
			matrixDisplayPanel.add(operation);
			
			matrixDisplayPanel.add(table2);
			calcButton = new JButton("Calculate Answer");
			calcButton.addActionListener(new calculateButtonListener());
			
			randomPopButton = new JButton("Populate Random Values");
			randomPopButton.addActionListener(new randomPopListener());
		
			buttonPanel = new JPanel();
			buttonPanel.setLayout(new GridLayout(2, 1));
			buttonPanel.add(calcButton);
			buttonPanel.add(randomPopButton);
			
			matrixDisplayPanel.add(buttonPanel);
			
			JLabel spacingHelp = new JLabel("  ");
			JLabel genHelp = new JLabel("--- Hit return/enter after adding input to each cell (ints/doubles only) ---");
			
			genHelp.setFont(new Font("Dialog", 1, 14));
			genHelp.setForeground(Color.black);
			genHelp.setAlignmentX(CENTER_ALIGNMENT);
			
			JLabel addHelp1 = new JLabel("Adding matrices requires matrices of the same dimensions: (R=Rows, C=Columns)");
			JLabel addHelp2 = new JLabel("Matrix 1 (R1xC1) -- Matrix 2 (R2xC2)");
			JLabel addHelp3 = new JLabel("Requirements for Addition: R1==R2  &&  C1==C2");
			
			addHelp1.setFont(new Font("Dialog", 1, 14));
			addHelp1.setForeground(Color.black);
			addHelp1.setAlignmentX(CENTER_ALIGNMENT);
			
			addHelp2.setFont(new Font("Dialog", 1, 14));
			addHelp2.setForeground(Color.black);
			addHelp2.setAlignmentX(CENTER_ALIGNMENT);
			
			addHelp3.setFont(new Font("Dialog", 1, 14));
			addHelp3.setForeground(Color.black);
			addHelp3.setAlignmentX(CENTER_ALIGNMENT);
			
			
			
			JLabel subHelp1 = new JLabel("Subtracting matrices requires matrices of the same dimensions: (R=Rows, C=Columns)");
			JLabel subHelp2 = new JLabel("Matrix 1 (R1xC1) -- Matrix 2 (R2xC2)");
			JLabel subHelp3 = new JLabel("Requirements for Subtraction: R1==R2  &&  C1==C2");
			
			subHelp1.setFont(new Font("Dialog", 1, 14));
			subHelp1.setForeground(Color.black);
			subHelp1.setAlignmentX(CENTER_ALIGNMENT);
			
			subHelp2.setFont(new Font("Dialog", 1, 14));
			subHelp2.setForeground(Color.black);
			subHelp2.setAlignmentX(CENTER_ALIGNMENT);
			
			subHelp3.setFont(new Font("Dialog", 1, 14));
			subHelp3.setForeground(Color.black);
			subHelp3.setAlignmentX(CENTER_ALIGNMENT);
			
			JLabel multHelp1 = new JLabel("Multiplying matrices requires matrices of the following dimensions: (R=Rows, C=Columns)");
			JLabel multHelp2 = new JLabel("Matrix 1 (R1xC1) -- Matrix 2 (R2xC2)");
			JLabel multHelp3 = new JLabel("Multiplying Requirements: C1==R2      Solution Matrix dimensions: R1xC2       Matrix1*Matrix2 != Matrix2*Matrix1");
			 
			multHelp1.setFont(new Font("Dialog", 1, 14));
			multHelp1.setForeground(Color.black);
			multHelp1.setAlignmentX(CENTER_ALIGNMENT);
			
			multHelp2.setFont(new Font("Dialog", 1, 14));
			multHelp2.setForeground(Color.black);
			multHelp2.setAlignmentX(CENTER_ALIGNMENT);
			
			multHelp3.setFont(new Font("Dialog", 1, 14));
			multHelp3.setForeground(Color.black);
			multHelp3.setAlignmentX(CENTER_ALIGNMENT);
			
			JLabel gaussHelp1 = new JLabel("Gauss Jordan Elimination Implementation uses a Coefficient Matrix of a Set of Equations, along with the Solution Vector");
			JLabel gaussHelp2 = new JLabel("(R=Rows, C=Columns) Matrix 1 = Coefficient Matrix (R1xC1)     Matrix 2 = Solution Vector (R2xC2)");
			JLabel gaussHelp3 = new JLabel("GJ Requirements: R1==C1 && R1==R2 && C2==1");
			
			gaussHelp1.setFont(new Font("Dialog", 1, 14));
			gaussHelp1.setForeground(Color.black);
			gaussHelp1.setAlignmentX(CENTER_ALIGNMENT);
			
			gaussHelp2.setFont(new Font("Dialog", 1, 14));
			gaussHelp2.setForeground(Color.black);
			gaussHelp2.setAlignmentX(CENTER_ALIGNMENT);
			
			gaussHelp3.setFont(new Font("Dialog", 1, 14));
			gaussHelp3.setForeground(Color.black);
			gaussHelp3.setAlignmentX(CENTER_ALIGNMENT);
			
			infoPanel.add(genHelp);
			infoPanel.add(spacingHelp);
			
			if(selectionOp == "+"){
				infoPanel.add(addHelp1);
				infoPanel.add(addHelp2);
				infoPanel.add(addHelp3);
			}
			else{
				if(selectionOp == "-"){
					infoPanel.add(subHelp1);
					infoPanel.add(subHelp2);
					infoPanel.add(subHelp3);
				}
				else{
					if(selectionOp == "x"){
						infoPanel.add(multHelp1);
						infoPanel.add(multHelp2);
						infoPanel.add(multHelp3);
					}
					else{
						if(selectionOp == "Gauss Jordan"){
							infoPanel.add(gaussHelp1);
							infoPanel.add(gaussHelp2);
							infoPanel.add(gaussHelp3);
						}
					}
					
				}
			}
			
			displayMatricesPanel.updateUI();
		}
	}
	
	private class randomPopListener implements ActionListener{
		public void actionPerformed(ActionEvent e){	
			solutionPanel.removeAll();
			solutionPanel.updateUI();
			
			int r1 = table1.getRowCount();
			int c1 = table1.getColumnCount();
			int r2 = table2.getRowCount();
			int c2 = table2.getColumnCount();
			
			for(int i=0; i<r1; i++){
				for(int j=0; j<c1; j++){
					Integer temp = (Integer)((int)(Math.random()*20));
					String temp2 = (String)(temp.toString());
					table1.setValueAt(temp2, i, j);
				}
			}
			
			for(int i=0; i<r2; i++){
				for(int j=0; j<c2; j++){
					Integer temp = (Integer)((int)(Math.random()*20));
					String temp2 = (String)(temp.toString());
					table2.setValueAt(temp2, i, j);
				}
			}
		}
	}
	
	private class calculateButtonListener implements ActionListener {
		public void actionPerformed(ActionEvent e){		
			solutionPanel.removeAll();
			solutionPanel.updateUI();
			
			solutionPanel.setLayout(new BoxLayout(solutionPanel, BoxLayout.Y_AXIS));
		
			JLabel spacing1 = new JLabel("  ");
			JLabel spacing2 = new JLabel("  ");
			JLabel spacing3 = new JLabel("  ");
			JLabel spacing4 = new JLabel("  ");
			JLabel spacing5 = new JLabel("  ");
			solutionPanel.add(spacing1);
			solutionPanel.add(spacing2);
			solutionPanel.add(spacing3);
			solutionPanel.add(spacing4);
			solutionPanel.add(spacing5);
			
			Double [][] A = new Double[selection1H][selection1W]; 
			
			try{
				for(int i=0; i<selection1H; i++){
					for(int j=0; j<selection1W; j++){
						A[i][j] = Double.parseDouble((String)table1.getValueAt(i, j));
					}
				}
				
				Double [][] B = new Double[selection2H][selection2W];
				for(int i=0; i<selection2H; i++){
					for(int j=0; j<selection2W; j++){
						B[i][j] = Double.parseDouble((String)table2.getValueAt(i, j));
					}
				}
				
				solutionMatrix = null;
				if(selectionOp == "+"){
					solutionMatrix = Matrix.matrixAdd(A, B);
					errorLabel = new JLabel("Cannot add Matrices (incompatible dimensions)");
				}
				else{
					if(selectionOp == "-"){
						solutionMatrix = Matrix.matrixSubtract(A, B);
						errorLabel = new JLabel("Cannot subtract Matrices (incompatible dimensions)");
					}
					else{
						if(selectionOp == "x"){
							solutionMatrix = Matrix.matrixMultiply(A, B);
							errorLabel = new JLabel("Cannot multiply Matrices (incompatible dimensions)");
						}
						else{
							if(selectionOp == "/"){
								solutionMatrix = Matrix.matrixDivide(A, B);
								errorLabel = new JLabel("Cannot divide Matrices (incompatible dimensions)");
							}
							else{
								if(selectionOp == "Gauss Jordan"){
									solutionMatrix = Matrix.GaussJordanElim(A, B);
									errorLabel = new JLabel("Cannot apply Gauss Jordan Elimination (incompatible dimensions or no unique solutions to the set of equations)");
									
								}
							}
						}
					}
				}
	
				errorLabel.setFont(new Font("Dialog", 1, 14));
				
				if(solutionMatrix != null){
					errorLabel = new JLabel("Solution Matrix");
					errorLabel.setFont(new Font("Dialog", 1, 14));
					errorLabel.setAlignmentX(CENTER_ALIGNMENT);
					
					table3 = new JTable(solutionMatrix.length, solutionMatrix[0].length);
					table3.setBackground(new Color(0x00746b));
					table3.setGridColor(Color.white);
					table3.setForeground(Color.white);
					table3.setFont(new Font("Dialog", 1, 14));
					table3.setAlignmentX(CENTER_ALIGNMENT);
			
					for(int i=0; i<solutionMatrix.length; i++){
						for(int j=0; j<solutionMatrix[0].length; j++){
							table3.setValueAt(solutionMatrix[i][j], i, j);
						}
					}
					
					
					if(selectionOp != "Gauss Jordan"){
						table3.setMinimumSize(new Dimension((table3.getRowCount()*74), (table3.getColumnCount()*16)));
						table3.setMaximumSize(new Dimension((table3.getRowCount()*74), (table3.getColumnCount()*16)));
					}
	
					solutionPanel.add(errorLabel);
					solutionPanel.add(Box.createRigidArea(new Dimension(0,15)));
					solutionPanel.add(table3);
					
				}
				else{
					errorLabel.setForeground(Color.red);
					errorLabel.setAlignmentX(CENTER_ALIGNMENT);
					solutionPanel.add(errorLabel);	
				}
				
				displayMatricesPanel.updateUI();
			}catch(NumberFormatException e1){
				JLabel errorLabel1 = new JLabel("Invalid input into the Matrices");
				errorLabel1.setForeground(Color.red);
				errorLabel1.setFont(new Font("Dialog", 1, 14));
				errorLabel1.setAlignmentX(CENTER_ALIGNMENT);
				solutionPanel.add(errorLabel1);	
			}
			
		}
	}
	
	
}
